import { Entity, EntityStatus } from './Entity';
import { World } from './World';
import { GenericLinkedList, GenericLinkedListNode } from './GenericLinkedList';
import { ArchetypeMaskUtil } from './Archetype';

// class ListHook<T> {
// }
// // s

export class EntityManager {
    // 对象池   
    private readonly _entityPool: EntityPool = new EntityPool();

    // id -> entity
    private readonly _entityMap: Map<number, Entity> = new Map();

    // 原型管理
    private readonly _archetypeEntity = new Map<bigint, GenericLinkedList<Entity>>();

    // 使用通用链表管理实体
    private readonly _entityList: GenericLinkedList<Entity> = new GenericLinkedList<Entity>();

    // 当前id
    private _entityId: number = 1;

    // 记录总创建的对象
    private _totalCreateCount: number = 0;

    // 维持对world的引用，方便进行与world的交互
    private readonly _world: World;

    constructor(world: World) {
        this._world = world;
    }

    get entityPool() {
        return this._entityPool;
    }

    get world() {
        return this._world;
    }

    getEntity(id: number) {
        return this._entityMap.get(id);
    }

    // 迁移原型
    public migrateArchetype(entity: Entity, oldComponentMask: bigint) {
        if (oldComponentMask != 0n) {
            this.removeEntityToArchetype(entity, oldComponentMask);
        }

        this.addEntityToArchetype(entity);
    }

    createEntity(initFunc: (entity: Entity) => void) {
        let entity = this._entityPool.get();
        if (!entity) {
            entity = new Entity(this._world);
        }
        entity.id = this._entityId++;
        initFunc(entity);

        // 添加到链表并保存节点引用
        const node = this._entityList.addLast(entity);
        entity.entityListNode = node;

        // 添加到map
        this._entityMap.set(entity.id, entity);

        // 添加到原型
        this.addEntityToArchetype(entity);

        // 设置状态
        entity.status = EntityStatus.Active;

        return entity;
    }

    addEntityToArchetype(entity: Entity) {
        if (entity.componentMask == 0n) {
            return;
        }

        let archetypeList = this._archetypeEntity.get(entity.componentMask);
        if (!archetypeList) {
            archetypeList = new GenericLinkedList<Entity>();
            this._archetypeEntity.set(entity.componentMask, archetypeList);
        }
        archetypeList.addLast(entity);
        entity.archetypeListNode = archetypeList.tail;
    }

    removeEntityToArchetype(entity: Entity, oldComponentMask: bigint) {
        if (!entity.archetypeListNode) {
            return;
        }

        const archetypeList = this._archetypeEntity.get(oldComponentMask);
        if (!archetypeList) {
            return;
        }

        archetypeList.remove(entity.archetypeListNode);
        entity.archetypeListNode = null;
    }

    public get entityCount() {
        return this._entityList.size;
    }

    public get totalCreateCount() {
        return this._totalCreateCount;
    }

    public get archetypeCount() {
        return this._archetypeEntity.size;
    }

    // 收集所有的entity
    public getAllEntities(array: Entity[]) {
        array.length = 0;
        this._entityList.forEach((node) => {
            if (node.data.status != EntityStatus.Destroyed) {
                array.push(node.data);
            }
        });
    }

    destroyEntity(entity: Entity) {
        entity.status = EntityStatus.Destroyed;
        this._entityPool.put(entity);

        // 从链表中移除
        if (entity.entityListNode) {
            this._entityList.remove(entity.entityListNode);
            entity.entityListNode = null;
        }

        // 从原型链表中移除
        if (entity.archetypeListNode) {
            const archetypeList = this._archetypeEntity.get(entity.componentMask);
            if (archetypeList) {
                archetypeList.remove(entity.archetypeListNode);
                entity.archetypeListNode = null;
            }
        }

        // 从map中移除
        this._entityMap.delete(entity.id);
    }

    /**
     * 通过mask查询所有的archetypes（masks）
     */
    queryArchetypesContains(archetype: bigint, results: bigint[]) {
        results.length = 0;

        for (let [mask, archetypeList] of this._archetypeEntity) {
            if (ArchetypeMaskUtil.contains(mask, archetype)) {
                results.push(mask);
            }
        }
    }

    getEntitiesByArchetype(archetype:bigint, results:Entity[]) {
        results.length = 0;
        const archetypeList = this._archetypeEntity.get(archetype);
        if (!archetypeList) {
            return;
        }
        archetypeList.forEach((entity) => {
            results.push(entity.data);
        });
    }
}

class EntityPool {
    private _entityPool: Entity[] = [];

    public get() {
        return this._entityPool.shift();
    }

    public put(entity: Entity) {
        this._entityPool.push(entity);
    }
}


